#include "list.h"
#include <valgrind/valgrind.h>

struct cell * pop_cell(struct list * list);


int isIn(struct list * list, int id) {
  struct cell * tmp;
  for(tmp = list->head; tmp != NULL; tmp = tmp->next)
    if(tmp->thread->id == id)
      return 1;

  return 0;
}

struct list * create (){

  struct list * list = malloc(sizeof(struct list));
  list->head = NULL; 
  list->tail = NULL;
  list->size = 0;
  return list;
}

void freeThread(thread_t thread) {
  free(thread->context->uc_stack.ss_sp);
  free(thread->context);
  free(thread);
}

void freeFIFO(struct list * list) {
  if(list != NULL) {
    struct cell * tmp = pop_cell(list);
    for(tmp; tmp != NULL; tmp = pop_cell(list)) {
      freeThread(tmp->thread);
      free(tmp);
    }
  }
  free(list->head);
  free(list);
}



int is_empty (struct list * list){
  return(list->head == NULL);
}

struct list * push (struct list * list, thread_t thread){
  if(list->head == NULL) {
    list->head = set_next(list->head, thread);
    list->tail = &list->head;
    (*list->tail)->next = NULL;
  }
  else if((*list->tail) == list->head){ 
    struct cell * tmp = malloc(sizeof(struct cell)); 
    tmp->thread = thread;
    tmp->next = NULL;
    list->head->next = tmp;
    list->tail = &(list->head->next);
  }
  else {
    struct cell * tmp = malloc(sizeof(struct cell)); 
    tmp->thread = thread;
    tmp->next = NULL;
    (*list->tail)->next = tmp;
    list->tail = &(*list->tail)->next;
  }
  list->size++;
  return list;
}

struct cell * pop_cell(struct list * list) {
  if( list != NULL) {
    if(list->head != NULL) {
      struct cell * tmp = list->head;
      list->head = list->head->next;
      return tmp;
    }
  }
  return NULL;
}

thread_t pop (struct list * list){
  if(list->head==NULL){
    printf("erreur de pop, liste vide\n");
    return NULL;
  }
  thread_t ret=list->head->thread;
  struct cell * tmp = list->head;
  list->head = list->head->next;
  if(tmp->next!=*list->tail){
    free(tmp);
  }
  list->size--;
  return ret;
}

int delete_thread(struct list *list){
  return is_empty(list) ? cell_destroy(list->head) : E_FAILURE;
}

int kill_thread(struct list* list, int id){
  return (list->head->thread->id == id) ? cell_destroy(list->head) : cell_kill(list->head,id);
}

int remove_thread(struct list * list, int id) {
  if(list->head == NULL){
    return E_FAILURE;
  }
  //le thread que l'on veut supprimer est sur le premier maillon de la liste, il faut donc deplacer la tete vers le maillon suivant
  if(list->head->thread->id == id) {
    //si la liste est constituee que d un maillon	
    if(list->head==*(list->tail)){
      list->tail==NULL;
      free(list->head);
      list->head=NULL;
    }
    //si la liste a plusieurs maillons
    else{
      struct cell * temp;
      temp=list->head;
      list->head=list->head->next;
      temp->next=NULL;
      free(temp);
    }
    list->size--;
    return E_SUCCESS;
  }
  //si le thread a supprimer se trouve sur un maillon au milieu de la liste
  struct cell * tmp=list->head;
  struct cell * tmp2;
  //on le localise en faisant les tests sur le next pour garder en memoire le maillon qui le precede
  for(tmp = list->head; tmp->next != NULL && tmp->next->thread->id != id; tmp = tmp->next);
  if(tmp->next == NULL)
    return E_FAILURE;

  tmp2 = tmp->next;
  //on raccorde le precedent en sautant celui que l'on ne veut plus
  //si le tmp->next est le dernier maillon il faut deplacer la queue vers l'arriere
  if(*list->tail==tmp2){
    tmp->next = NULL;
    list->tail=&tmp;
  }
  else
    tmp->next = tmp->next->next;

  //on efface le maillon inutile
  if(*list->tail!=tmp2->next)
    free(tmp2);	

  list->size--;

  return E_SUCCESS;
}

void debug_list(struct list *l){
  struct cell *tmp;
  for(tmp = l->head; tmp != NULL; tmp = tmp->next){
    cell_debug(tmp);   
  }
  printf("\n");
}
